<template>
    <div class="goods-sku">
        <dl v-for="item in goods.specs" :key="item.id">
            <dt>{{item.name}}</dt>
            <dd>
                <a v-for="val in item.values" :key="val.name">
                    <img :class="{selected:val.selected,disabled:val.disabled}" @click="changeSku(item,val)"
                         v-if="val.picture" :src="val.picture" :title="val.name">
                    <span :class="{selected:val.selected,disabled:val.disabled}" @click="changeSku(item,val)" v-else>{{val.name}}</span>
                </a>
            </dd>
        </dl>
    </div>
</template>
<script>
    import powerSet from '@/vender/power-set'
    import {findGoods} from "@/api/product";

    const spliter = '★'

    export default {
        name: 'GoodsSku',
        props: {
            goodsId: {
                type: String,
                default: {}
            },
            skuId: {
                type: String,
                default: ''
            }
        },
        data() {
            return {
                pathMap: {},
                goods:{}
            }
        },
        created() {
            this.findGoods()
        },
        methods: {
            // 获取商品详情
            async findGoods() {

                const {result} = await findGoods(this.goodsId)
                result.specs.map(item =>{
                    item.values.map(sub=>{
                        sub.disabled=true
                        sub.selected=false
                    })
                })
                this.goods = result

                this.pathMap = this.getPathMap(this.goods.skus)
                // 根据skuId初始化选中
                if (this.skuId) {
                    this.initDefaultSelected(this.goods, this.skuId)
                }
                // ☆组件初始化：更新按钮禁用状态
                this.updateDisabledStatus(this.goods.specs, this.pathMap)
            },

            // 1. 选中与取消选中，约定在每一个按钮都拥有自己的选中状态数据：selected
            // 1.1 点击的是已选中，只需要取消当前的选中
            // 1.2 点击的是未选中，把同一个规格的按钮改成未选中，当前点击的改成选中
            changeSku(item, val) {

                // 当按钮是禁用的阻止程序运行
                if (val.disabled) return
                // 如果不是禁用正常运行
                if (val.selected) {
                    val.selected = false
                } else {
                    item.values.forEach(valItem => {
                        valItem.selected = false
                    })
                    val.selected = true
                }
                // ☆点击按钮时：更新按钮禁用状态
                this.updateDisabledStatus(this.goods.specs, this.pathMap)
                // 将你选择的sku信息通知父组件{skuId,price,oldPrice,inventory,specsText}
                // 1. 选择完整的sku组合按钮，才可以拿到这些信息，提交父组件
                // 2. 不是完整的sku组合按钮，提交空对象父组件
                const validSelectedValues = this.getSelectedValues(this.goods.specs).filter(v => v)
                if (validSelectedValues.length === this.goods.specs.length) {
                    // 完整
                    const skuIds = this.pathMap[validSelectedValues.join(spliter)]
                    const sku = this.goods.skus.find(sku => sku.id === skuIds[0])
                    this.$emit('change', {
                        skuId: sku.id,
                        price: sku.price,
                        oldPrice: sku.oldPrice,
                        inventory: sku.inventory,
                        // 属性名：属性值 属性名1：属性值1 ... 这样的字符串
                        specsText: sku.specs.reduce((p, c) => `${p} ${c.name}：${c.valueName}`, '').trim()
                    })
                } else {
                    // 不完整
                    // 父组件需要判断是否规格选择完整，不完整不能加购物车。
                    this.$emit('change', {})
                }
            },
            // 得到一个路径字典对象
            getPathMap(skus) {
                // 1. 得到所有的sku集合  props.goods.skus
                // 2. 从所有的sku中筛选出有效的sku
                // 3. 根据有效的sku使用power-set算法得到子集
                // 4. 根据子集往路径字典对象中存储 key-value
                const pathMap = {}
                skus.forEach(sku => {
                    if (sku.inventory > 0) {
                        // 计算当前有库存的sku的子集
                        // 例如：[1,2,3] ==> [[1],[2],[3],[1,2],[1,3],[2,3],[1,2,3]]
                        // 可选值数组
                        const valueArr = sku.specs.map(val => val.valueName)
                        // 可选值数组 子集
                        const valueArrPowerSet = powerSet(valueArr)
                        // 遍历子集，往pathMap插入数据
                        valueArrPowerSet.forEach(arr => {
                            // 根据arr得到字符串的key，约定key是：['蓝色','美国'] ===> '蓝色★美国'
                            const key = arr.join(spliter)

                            // 给pathMap设置数据
                            if (pathMap[key]) {
                                pathMap[key].push(sku.id)
                            } else {
                                pathMap[key] = [sku.id]
                            }
                        })
                    }
                })
                return pathMap
            },
            // 获取已选中的值数组
            getSelectedValues(specs) {
                const arr = []
                specs.forEach(item => {
                    // 选中的按钮对象
                    const seletedVal = item.values.find(val => val.selected)
                    arr.push(seletedVal ? seletedVal.name : undefined)
                })
                return arr
            },
            // 更新按钮禁用状态
            updateDisabledStatus(specs, pathMap) {
                // 1. 约定每一个按钮的状态由本身的disabled数据来控制
                specs.forEach((item, i) => {
                    const selectedValues = this.getSelectedValues(specs)
                    item.values.forEach(val => {
                        // 2. 判断当前是否选中，是选中不用判断
                        if (val.selected) return
                        // 3. 拿当前的值按照顺序套入选中的值数组
                        selectedValues[i] = val.name
                        // 4. 剔除undefined数据，按照分隔符拼接key
                        const key = selectedValues.filter(value => value).join(spliter)
                        // 5. 拿着key去路径字典中查找是否有数据，有可以点击，没有就禁用（true）
                        val.disabled = !pathMap[key]
                    })
                })
            },
            // 默认选中
            initDefaultSelected(goods, skuId) {
                // 1. 找出sku的信息
                // 2. 遍历每一个按钮，按钮的值和sku记录的值相同，就选中。
                const sku = goods.skus.find(sku => sku.id === skuId)
                goods.specs.forEach((item, i) => {
                    const val = item.find(val => val.name === sku.specs[i].valueName)
                    val.selected = true
                })
            }
        }

    }
</script>
<style scoped lang="less">
    .sku-state-mixin () {
        border: 1px solid #e4e4e4;
        margin-right: 10px;
        cursor: pointer;
        &.selected {
            border-color: @xtxColor;
        }
        &.disabled {
            opacity: 0.6;
            border-style: dashed;
            cursor: not-allowed;
        }
    }

    .goods-sku {
        padding-left: 10px;
        padding-top: 20px;

        dl {
            display: flex;
            padding-bottom: 10px;
            align-items: center;

            dt {
                width: 50px;
                color: #999;
            }

            dd {
                flex: 1;
                color: #666;
                line-height: 40px;

                img {
                    width: 50px;
                    height: 50px;
                    .sku-state-mixin ();
                }

                span {
                    display: inline-block;
                    height: 30px;
                    line-height: 28px;
                    padding: 0 20px;
                    .sku-state-mixin ();
                }
            }
        }
    }
</style>
